/*
 * Copyright 2002-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.aop;

import java.lang.reflect.Method;

/**
 * Part of a {@link Pointcut}: Checks whether the target method is eligible for advice.
 *
 * <p>A MethodMatcher may be evaluated <b>statically</b> or at <b>runtime</b> (dynamically).
 * Static matching involves method and (possibly) method attributes. Dynamic matching
 * also makes arguments for a particular call available, and any effects of running
 * previous advice applying to the joinpoint.
 *
 * <p>If an implementation returns {@code false} from its {@link #isRuntime()}
 * method, evaluation can be performed statically, and the result will be the same
 * for all invocations of this method, whatever their arguments. This means that
 * if the {@link #isRuntime()} method returns {@code false}, the 3-arg
 * {@link #matches(java.lang.reflect.Method, Class, Object[])} method will never be invoked.
 *
 * <p>If an implementation returns {@code true} from its 2-arg
 * {@link #matches(java.lang.reflect.Method, Class)} method and its {@link #isRuntime()} method
 * returns {@code true}, the 3-arg {@link #matches(java.lang.reflect.Method, Class, Object[])}
 * method will be invoked <i>immediately before each potential execution of the related advice</i>,
 * to decide whether the advice should run. All previous advice, such as earlier interceptors
 * in an interceptor chain, will have run, so any state changes they have produced in
 * parameters or ThreadLocal state will be available at the time of evaluation.
 *
 * <p>Concrete implementations of this interface typically should provide proper
 * implementations of {@link Object#equals(Object)} and {@link Object#hashCode()}
 * in order to allow the matcher to be used in caching scenarios &mdash; for
 * example, in proxies generated by CGLIB.
 *
 * @author Rod Johnson
 * @since 11.11.2003
 * @see Pointcut
 * @see ClassFilter
 */
/*
1. 总结
	MethodMatcher 是 Spring AOP 框架中的一个核心接口，用于判断目标方法是否符合切点条件。
	它支持静态匹配和动态匹配两种模式，可以根据需要在编译时或运行时进行方法匹配。
	该接口是 Pointcut 接口的一部分，与 ClassFilter 共同定义了完整的切点逻辑。
2. 内部成员说明
方法
	matches(Method method, Class<?> targetClass): 执行静态检查，判断给定方法是否匹配。如果返回 false 或 isRuntime() 返回 false，则不会执行运行时检查。
	isRuntime(): 判断 MethodMatcher 是否是动态的。如果返回 true，即使静态匹配通过，也需要在运行时调用 matches(Method method, Class<?> targetClass, Object... args) 进行最终确认。
	matches(Method method, Class<?> targetClass, Object... args): 执行运行时（动态）匹配检查，仅在静态匹配通过且 isRuntime() 返回 true 时调用。在执行相关增强器之前立即调用，此时之前的增强器已经运行，可以访问它们产生的状态变化。
	TRUE: 静态字段，表示一个匹配所有方法的 MethodMatcher 实例。
3. 类关系结构
	MethodMatcher	用于判断目标方法是否符合切点条件。它支持静态匹配和动态匹配两种模式
	├── TrueMethodMatcher	表示一个匹配所有方法的 Matcher 实例。它是 MethodMatcher.TRUE 静态字段的实现。
	├── StaticMethodMatcher		 MethodMatcher 的抽象基类，提供了静态匹配的默认实现。
	│   ├── StaticMethodMatcherPointcut	 StaticMethodMatcher 的具体实现，用于实现静态方法匹配的切点。
	│   │   ├── AbstractRegexMethodPointcut	 基于正则表达式的抽象方法匹配器，提供了正则表达式匹配的通用功能。
	│   │   │   └── JdkRegexpMethodPointcut	 AbstractRegexMethodPointcut 的具体实现，使用 JDK 的正则表达式引擎进行方法匹配。
	│   │   ├── AnnotationMethodMatcher	基于注解的方法匹配器，用于匹配带有特定注解的方法。
	│   │   ├── NameMatchMethodPointcut	方法名的方法匹配器，可以配置要匹配的方法名列表。
	│   │   ├── TransactionAttributeSourcePointcut	事务属性源切点，用于匹配具有事务属性的方法。
	│   │   └── JCacheOperationSourcePointcut	 JCache 操作源切点，用于匹配 JCache 相关的操作。
	│   └── StaticMethodMatcherPointcutAdvisor	静态方法匹配器的顾问，将切点与增强器关联起来。
	├── DynamicMethodMatcher	MethodMatcher 的抽象基类，提供了动态匹配的默认实现。
	│   └── DynamicMethodMatcherPointcut	 DynamicMethodMatcher 的具体实现，用于实现动态方法匹配的切点。
	├── IntroductionAwareMethodMatcher	MethodMatcher 的子接口，增加了对引入（introduction）的支持。
	│   └── AspectJExpressionPointcut	 IntroductionAwareMethodMatcher 的具体实现，支持 AspectJ 表达式的切点匹配。
	└── ControlFlowPointcut	基于控制流的切点，根据调用栈等信息进行匹配。

	相关类和接口关系说明
		Pointcut: 包含 MethodMatcher 和 ClassFilter，共同定义了切点逻辑。
		ClassFilter: 与 MethodMatcher 配合使用，先过滤类，再匹配方法。
		IntroductionAwareMethodMatcher: MethodMatcher 的子接口，增加了对引入（introduction）的支持。
4. 使用场景
	在 Spring AOP 中定义切点，判断哪些方法需要应用增强器。
	实现基于方法名、正则表达式或其他条件的方法匹配。
	支持静态和动态匹配，提高性能和灵活性。
	与 ClassFilter 结合使用，实现复杂的切点逻辑。
5. 实际代码应用示例
// 创建一个基于方法名的 MethodMatcher
public class NameMatchMethodPointcut implements MethodMatcher {

    private String methodName;

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        return method.getName().equals(methodName);
    }

    @Override
    public boolean isRuntime() {
        return false; // 静态匹配
    }

    @Override
    public boolean matches(Method method, Class<?> targetClass, Object... args) {
        // 不需要运行时匹配
        return true;
    }
}

// 使用 MethodMatcher 创建 Pointcut
public class MyPointcut implements Pointcut {

    private NameMatchMethodPointcut methodMatcher;

    public void setMethodMatcher(NameMatchMethodPointcut methodMatcher) {
        this.methodMatcher = methodMatcher;
    }

    @Override
    public ClassFilter getClassFilter() {
        return ClassFilter.TRUE; // 匹配所有类
    }

    @Override
    public MethodMatcher getMethodMatcher() {
        return methodMatcher;
    }
}


 */
public interface MethodMatcher {

	/**
	 * Perform static checking whether the given method matches.
	 * <p>If this returns {@code false} or if the {@link #isRuntime()}
	 * method returns {@code false}, no runtime check (i.e. no
	 * {@link #matches(java.lang.reflect.Method, Class, Object[])} call)
	 * will be made.
	 * @param method the candidate method
	 * @param targetClass the target class
	 * @return whether or not this method matches statically
	 */
	boolean matches(Method method, Class<?> targetClass);

	/**
	 * Is this MethodMatcher dynamic, that is, must a final call be made on the
	 * {@link #matches(java.lang.reflect.Method, Class, Object[])} method at
	 * runtime even if the 2-arg matches method returns {@code true}?
	 * <p>Can be invoked when an AOP proxy is created, and need not be invoked
	 * again before each method invocation,
	 * @return whether or not a runtime match via the 3-arg
	 * {@link #matches(java.lang.reflect.Method, Class, Object[])} method
	 * is required if static matching passed
	 */
	boolean isRuntime();

	/**
	 * Check whether there a runtime (dynamic) match for this method,
	 * which must have matched statically.
	 * <p>This method is invoked only if the 2-arg matches method returns
	 * {@code true} for the given method and target class, and if the
	 * {@link #isRuntime()} method returns {@code true}. Invoked
	 * immediately before potential running of the advice, after any
	 * advice earlier in the advice chain has run.
	 * @param method the candidate method
	 * @param targetClass the target class
	 * @param args arguments to the method
	 * @return whether there's a runtime match
	 * @see MethodMatcher#matches(Method, Class)
	 */
	boolean matches(Method method, Class<?> targetClass, Object... args);


	/**
	 * Canonical instance that matches all methods.
	 */
	MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;

}
